﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Net;
using Dokan;
using Newtonsoft.Json;

namespace ShareFS
{
    internal class Program
    {
        public static void Main(string[] args)
        {
            var opt = new DokanOptions
                          {
                              MountPoint = "s:\\",
                              DebugMode = true,
                              UseStdErr = true,
                              VolumeLabel = "ShareFS"
                          };
            int status = DokanNet.DokanMain(opt, new TestFs());
            switch (status)
            {
                case DokanNet.DOKAN_DRIVE_LETTER_ERROR:
                    Console.WriteLine("Drvie letter error");
                    break;
                case DokanNet.DOKAN_DRIVER_INSTALL_ERROR:
                    Console.WriteLine("Driver install error");
                    break;
                case DokanNet.DOKAN_MOUNT_ERROR:
                    Console.WriteLine("Mount error");
                    break;
                case DokanNet.DOKAN_START_ERROR:
                    Console.WriteLine("Start error");
                    break;
                case DokanNet.DOKAN_ERROR:
                    Console.WriteLine("Unknown error");
                    break;
                case DokanNet.DOKAN_SUCCESS:
                    Console.WriteLine("Success");
                    break;
                default:
                    Console.WriteLine("Unknown status: {0}", status);
                    break;
            }
        }
    }

    internal class TestFs : DokanOperations
    {
        private readonly IDictionary<string, string> urlById = new Dictionary<string, string>();
        private readonly IDictionary<string, byte[]> imageById = new Dictionary<string, byte[]>();
        #region DokanOperations member

        public int Cleanup(string filename, DokanFileInfo info)
        {
            return 0;
        }

        public int CloseFile(string filename, DokanFileInfo info)
        {
            return 0;
        }

        public int CreateDirectory(string filename, DokanFileInfo info)
        {
            return -1;
        }

        public int CreateFile(
            string filename,
            FileAccess access,
            FileShare share,
            FileMode mode,
            FileOptions options,
            DokanFileInfo info)
        {
            return 0;
        }

        public int DeleteDirectory(string filename, DokanFileInfo info)
        {
            return -1;
        }

        public int DeleteFile(string filename, DokanFileInfo info)
        {
            return -1;
        }


        public int FlushFileBuffers(
            string filename,
            DokanFileInfo info)
        {
            return -1;
        }

        public int FindFiles(
            string filename,
            ArrayList files,
            DokanFileInfo info)
        {
            try
            {
                using (var client = new WebClient())
                {
                    client.Credentials = new NetworkCredential("a.v.safonov@gmail.com", "qwerty");
                    string response = client.DownloadString("http://localhost:8080/api/content/picasa");
                    var items = JsonConvert.DeserializeObject<IList<PhotoItem>>(response);
                    urlById.Clear();
                    int cnt = 0;
                    foreach (var item in items)
                    {
                        if (cnt < 10)
                        {
                            urlById[item.photoId] = item.uri;
                            cnt++;
                        }
                        
                    }
                }
            }
            catch (Exception)
            {
            }

            foreach (var idToUri in urlById)
            {
                LoadFile(idToUri.Key);
                files.Add(new FileInformation
                              {
                                  FileName = idToUri.Key + ".jpg",
                                  Attributes = FileAttributes.Normal | FileAttributes.ReadOnly,
                                  LastAccessTime = DateTime.Now,
                                  LastWriteTime = DateTime.Now,
                                  CreationTime = DateTime.Now,
                                  Length = imageById[idToUri.Key].Length
                              });
            }

            return 0;
        }


        public int GetFileInformation(
            string filename,
            FileInformation fileinfo,
            DokanFileInfo info)
        {
            if (filename == "\\")
            {
                fileinfo.Attributes = FileAttributes.Directory;
                fileinfo.LastAccessTime = DateTime.Now;
                fileinfo.LastWriteTime = DateTime.Now;
                fileinfo.CreationTime = DateTime.Now;

                return 0;
            }

            fileinfo.Attributes = FileAttributes.Normal | FileAttributes.ReadOnly;
            fileinfo.LastAccessTime = DateTime.Now;
            fileinfo.LastWriteTime = DateTime.Now;
            fileinfo.CreationTime = DateTime.Now;
            fileinfo.Length = imageById[GetFileId(filename)].Length;

            return 0;
        }

        public int LockFile(
            string filename,
            long offset,
            long length,
            DokanFileInfo info)
        {
            return 0;
        }

        public int MoveFile(
            string filename,
            string newname,
            bool replace,
            DokanFileInfo info)
        {
            return -1;
        }

        public int OpenDirectory(string filename, DokanFileInfo info)
        {
            return 0;
        }

        public int ReadFile(
            string filename,
            byte[] buffer,
            ref uint readBytes,
            long offset,
            DokanFileInfo info)
        {
            try
            {
                string id = GetFileId(filename);
                LoadFile(id);
                byte[] image = imageById[id];
                readBytes = (uint) Math.Min(buffer.Length, image.Length - offset);
                for (int i = 0; i < readBytes; i++)
                {
                    buffer[i] = image[i + offset];
                }

                return 0;
            }
            catch (Exception)
            {
                return -1;
            }
        }

        private static string GetFileId(string filename)
        {
            return filename.Substring(1, filename.Length - 5);
        }

        private void LoadFile(string id)
        {
            lock (imageById)
            {
                if (!imageById.ContainsKey(id))
                {
                    string uri = urlById[id];
                    using (var client = new WebClient())
                    {
                        imageById[id] = client.DownloadData(uri);
                    }
                }
            }
            
        }

        public int SetEndOfFile(string filename, long length, DokanFileInfo info)
        {
            return -1;
        }

        public int SetAllocationSize(string filename, long length, DokanFileInfo info)
        {
            return -1;
        }

        public int SetFileAttributes(
            string filename,
            FileAttributes attr,
            DokanFileInfo info)
        {
            return -1;
        }

        public int SetFileTime(
            string filename,
            DateTime ctime,
            DateTime atime,
            DateTime mtime,
            DokanFileInfo info)
        {
            return -1;
        }

        public int UnlockFile(string filename, long offset, long length, DokanFileInfo info)
        {
            return 0;
        }

        public int Unmount(DokanFileInfo info)
        {
            return 0;
        }

        public int GetDiskFreeSpace(
            ref ulong freeBytesAvailable,
            ref ulong totalBytes,
            ref ulong totalFreeBytes,
            DokanFileInfo info)
        {
            freeBytesAvailable = 512*1024*1024;
            totalBytes = 1024*1024*1024;
            totalFreeBytes = 512*1024*1024;
            return 0;
        }

        public int WriteFile(
            string filename,
            byte[] buffer,
            ref uint writtenBytes,
            long offset,
            DokanFileInfo info)
        {
            return -1;
        }

        #endregion
    }

    class PhotoItem
    {
        public string uri { get; set; }
        public string photoId { get; set; }
    }
}